import CryptoJS from 'crypto-js'

export interface SparkConfig {
  appId: string
  apiKey: string
  apiSecret: string
  domain?: string
  version?: string
}

export interface SparkMessage {
  role: 'system' | 'user' | 'assistant'
  content: string
}

export interface SparkResponse {
  header: {
    code: number
    message: string
    status: number
  }
  payload: {
    choices: {
      text: Array<{
        content: string
        role: string
        index: number
      }>
    }
    usage?: {
      text: {
        question_tokens: number
        prompt_tokens: number
        completion_tokens: number
        total_tokens: number
      }
    }
  }
}

export class XunfeiSpark {
  private config: SparkConfig
  private websocket: WebSocket | null = null
  private messageHistory: SparkMessage[] = []

  constructor(config: SparkConfig) {
    this.config = {
      domain: 'generalv3.5', // Spark Max 版本
      version: 'v3.5/chat',
      ...config
    }
  }

  /**
   * 生成WebSocket认证URL <mcreference link="https://www.xfyun.cn/doc/spark/Web.html" index="1">1</mcreference>
   */
  private generateAuthUrl(): string {
    const url = `wss://spark-api.xf-yun.com/${this.config.version}`
    const host = 'spark-api.xf-yun.com'
    const date = new Date().toUTCString()
    const algorithm = 'hmac-sha256'
    const headers = 'host date request-line'
    
    // 构建签名原文
    const signatureOrigin = `host: ${host}\ndate: ${date}\nGET /${this.config.version} HTTP/1.1`
    
    // 使用HMAC-SHA256生成签名
    const signatureSha = CryptoJS.HmacSHA256(signatureOrigin, this.config.apiSecret)
    const signature = CryptoJS.enc.Base64.stringify(signatureSha)
    
    // 构建authorization
    const authorizationOrigin = `api_key="${this.config.apiKey}", algorithm="${algorithm}", headers="${headers}", signature="${signature}"`
    const authorization = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(authorizationOrigin))
    
    return `${url}?authorization=${authorization}&date=${encodeURIComponent(date)}&host=${host}`
  }

  /**
   * 发送消息到星火大模型 <mcreference link="https://blog.csdn.net/weixin_52577523/article/details/142051874" index="3">3</mcreference>
   */
  async sendMessage(
    message: string,
    systemPrompt?: string,
    onMessage?: (content: string, isComplete: boolean) => void,
    onError?: (error: string) => void
  ): Promise<string> {
    return new Promise((resolve, reject) => {
      try {
        const authUrl = this.generateAuthUrl()
        this.websocket = new WebSocket(authUrl)
        
        let fullResponse = ''
        
        this.websocket.onopen = () => {
          // 添加系统提示词（如果提供）
          if (systemPrompt && this.messageHistory.length === 0) {
            this.messageHistory.push({
              role: 'system',
              content: systemPrompt
            })
          }
          
          // 添加用户消息
          this.messageHistory.push({
            role: 'user',
            content: message
          })
          
          // 构建请求参数 - 确保符合星火大模型官方API格式
          const params = {
            header: {
              app_id: this.config.appId,
              uid: Date.now().toString()
            },
            parameter: {
              chat: {
                domain: this.config.domain || 'generalv3.5',
                temperature: 0.7,
                max_tokens: 2048,
                auditing: 'default'
              }
            },
            payload: {
              message: {
                text: this.messageHistory.map(msg => {
                  // 确保消息格式严格符合API要求
                  if (!msg.role || !msg.content) {
                    throw new Error('消息格式不正确：缺少role或content字段')
                  }
                  return {
                    role: msg.role,
                    content: String(msg.content).trim() // 确保content是字符串且去除首尾空格
                  }
                })
              }
            }
          }
          
          // 验证消息数组不为空
          if (!params.payload.message.text || params.payload.message.text.length === 0) {
            throw new Error('消息内容不能为空')
          }
          
          console.log('发送到星火大模型的参数:', JSON.stringify(params, null, 2))
          this.websocket?.send(JSON.stringify(params))
        }
        
        this.websocket.onmessage = (event) => {
          try {
            // 验证消息数据有效性
            if (!event.data || typeof event.data !== 'string') {
              console.error('WebSocket消息数据无效:', event.data)
              const errorMsg = 'WebSocket消息数据格式错误'
              onError?.(errorMsg)
              reject(new Error(errorMsg))
              return
            }

            const response: SparkResponse = JSON.parse(event.data)
            
            // 验证响应结构的基本字段
            if (!response || typeof response !== 'object') {
              const errorMsg = '星火大模型响应数据格式异常: 响应不是有效的对象'
              console.error('响应格式错误:', response)
              onError?.(errorMsg)
              reject(new Error(errorMsg))
              return
            }

            if (!response.header || typeof response.header !== 'object') {
              const errorMsg = '星火大模型响应数据格式异常: 缺少header字段'
              console.error('响应缺少header:', response)
              onError?.(errorMsg)
              reject(new Error(errorMsg))
              return
            }
            
            // 详细的错误处理
            if (response.header.code !== 0) {
              let errorMsg = `星火大模型错误: ${response.header.code} - ${response.header.message}`
              
              // 针对特定错误码提供更详细的处理
              switch (response.header.code) {
                case 10004:
                  errorMsg = '星火大模型错误: 消息内容格式不正确，请检查输入内容'
                  break
                case 10013:
                  errorMsg = '星火大模型错误: 非法参数，请检查API配置'
                  break
                case 11200:
                  errorMsg = '星火大模型错误: 授权失败，请检查API密钥'
                  break
                case 11201:
                  errorMsg = '星火大模型错误: 日期格式错误'
                  break
                default:
                  errorMsg = `星火大模型错误: ${response.header.code} - ${response.header.message}`
              }
              
              console.error('星火大模型API错误:', response)
              onError?.(errorMsg)
              reject(new Error(errorMsg))
              return
            }
            
            // 检查响应结构是否正确
            if (!response.payload || !response.payload.choices || !response.payload.choices.text || !Array.isArray(response.payload.choices.text)) {
              const errorMsg = '星火大模型响应格式异常: 缺少必要的响应字段'
              console.error('响应结构异常:', response)
              onError?.(errorMsg)
              reject(new Error(errorMsg))
              return
            }
            
            // 获取返回的文本内容
            const textArray = response.payload.choices.text
            if (textArray.length === 0) {
              console.warn('星火大模型返回空内容')
              return
            }
            
            const content = textArray[0]?.content || ''
            fullResponse += content
            
            // 实时回调
            onMessage?.(content, response.header.status === 2)
            
            // 如果是最后一条消息
            if (response.header.status === 2) {
              // 添加AI回复到历史记录
              this.messageHistory.push({
                role: 'assistant',
                content: fullResponse
              })
              
              // 限制历史记录长度，避免token超限
              this.limitHistoryLength()
              
              this.websocket?.close()
              resolve(fullResponse)
            }
          } catch (error) {
            const errorMsg = `解析星火大模型响应失败: ${error}`
            console.error('解析响应错误:', error, '原始数据:', event.data)
            onError?.(errorMsg)
            reject(new Error(errorMsg))
          }
        }
        
        this.websocket.onerror = (error) => {
          const errorMsg = `WebSocket连接错误: ${error}`
          onError?.(errorMsg)
          reject(new Error(errorMsg))
        }
        
        this.websocket.onclose = (event) => {
          if (event.code !== 1000) {
            const errorMsg = `WebSocket连接异常关闭: ${event.code} - ${event.reason}`
            onError?.(errorMsg)
            reject(new Error(errorMsg))
          }
        }
        
      } catch (error) {
        const errorMsg = `发送消息失败: ${error}`
        onError?.(errorMsg)
        reject(new Error(errorMsg))
      }
    })
  }

  /**
   * 限制历史记录长度，避免token超限
   */
  private limitHistoryLength() {
    let totalLength = 0
    for (const msg of this.messageHistory) {
      totalLength += msg.content.length
    }
    
    // 如果总长度超过10000字符，删除最早的对话（保留system消息）
    while (totalLength > 10000 && this.messageHistory.length > 1) {
      // 找到第一个非system消息并删除
      for (let i = 0; i < this.messageHistory.length; i++) {
        if (this.messageHistory[i].role !== 'system') {
          const removed = this.messageHistory.splice(i, 1)[0]
          totalLength -= removed.content.length
          break
        }
      }
      
      // 如果只剩system消息，跳出循环
      if (this.messageHistory.every(msg => msg.role === 'system')) {
        break
      }
    }
  }

  /**
   * 清空对话历史
   */
  clearHistory() {
    this.messageHistory = []
  }

  /**
   * 获取对话历史
   */
  getHistory(): SparkMessage[] {
    return [...this.messageHistory]
  }

  /**
   * 关闭WebSocket连接
   */
  close() {
    if (this.websocket) {
      this.websocket.close()
      this.websocket = null
    }
  }

  /**
   * 检查浏览器是否支持WebSocket
   */
  static isSupported(): boolean {
    return typeof WebSocket !== 'undefined'
  }
}

export default XunfeiSpark